#ifndef __SOCKET_HPP__
#define __SOCKET_HPP__

#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include "log.hpp"

static const int MAX_LISTEN = 1024; // 全连接的最大数量
class Socket
{
public:
    Socket() : _sockfd(-1)
    {
    }
    Socket(int fd) : _sockfd(fd)
    {
    }
    ~Socket()
    {
        Close();
    }
    /* 获取文件描述符 */
    int Fd() const
    {
        return _sockfd;
    }
    /* 创建套接字 */
    bool Create()
    {
        if(_sockfd >= 0) 
            return true;

        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            ERR_LOG("socket create socket failed [%d]: %s", errno, strerror(errno));
            return false;
        }
        return true;
    }
    /* 绑定地址信息 */
    bool Bind(const std::string &ip, const uint16_t port)
    {
        struct sockaddr_in addr;
        bzero(&addr, sizeof(addr));

        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(ip.c_str());
        socklen_t len = sizeof(addr);
        int ret = bind(_sockfd, (struct sockaddr *)&addr, len);
        if (ret < 0)
        {
            ERR_LOG("socket [%d] bind failed [%d]: %s", _sockfd, errno, strerror(errno));
            return false;
        }
        return true;
    }
    /* 开始监听 */
    bool Listen(const int backlog = MAX_LISTEN)
    {
        int ret = listen(_sockfd, backlog);
        if (ret < 0)
        {
            ERR_LOG("socket listen failed [%d]: %s", errno, strerror(errno));
            return false;
        }
        return true;
    }
    /* 向服务器发起连接 */
    bool Connect(const std::string &ip, const uint16_t port)
    {
        struct sockaddr_in addr;
        bzero(&addr, sizeof(addr));

        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(ip.c_str());
        addr.sin_port = htons(port);

        socklen_t len = sizeof(addr);
        int ret = connect(_sockfd, (struct sockaddr *)&addr, len);
        if (ret < 0)
        {
            ERR_LOG("socket connect failed [%d]: %s", errno, strerror(errno));
            return false;
        }
        return true;
    }
    /* 获取新连接 */
    int Accept()
    {
        int sockfd = accept(_sockfd, nullptr, nullptr);
        if (sockfd < 0)
            ERR_LOG("socket accept failed [%d]: %s", errno, strerror(errno));
        return sockfd;
    }
    /* 接收数据 */
    ssize_t Recv(void *buf, size_t len, int flag = 0)
    {
        ssize_t n = recv(_sockfd, buf, len, flag);// falg=0,阻塞式接收

        if (n <= 0)
        {
            // EAGIN：当前socket的接收缓冲区中没有数据，只有在非阻塞的情况下才会出现
            // EINTR：当前socket的阻塞等待被信号中断
            if (errno == EAGAIN || errno == EINTR)
                return 0; // 没有接收到数据，但没有错误

            ERR_LOG("socket recv failed [%d]: %s", errno, strerror(errno));
            return -1;// 将连接关闭也归属到接收异常中，这是为了返回0没有歧义，只代表正常读取但没读取到数据
        }
        return n; // 实际接收到的数据长度
    }
    /* 接收数据——非阻塞式 */
    ssize_t NonBlockRecv(void *buf, size_t len)
    {
        if(len == 0) return 0;
        // MSG_DONTWAIT：当前IO为非阻塞方式
        return Recv(buf, len, MSG_DONTWAIT);
    }
    /* 发送数据 */
    ssize_t Send(const void *buf, size_t len, int flag = 0)
    {
        ssize_t n = send(_sockfd, buf, len, flag);
        if(n < 0)
        {
            // EAGIN：当前socket的发送缓冲区中没有数据，只有在非阻塞的情况下才会出现
            // EINTR：当前socket的阻塞等待被信号中断
            if (errno == EAGAIN || errno == EINTR)
                return 0; // 没有接收到数据，但没有错误

            ERR_LOG("socket send failed [%d]: %s", errno, strerror(errno));
            return -1;
        }

        return n;// 实际发送的数据长度 or -1
    }
    /* 发送数据——非阻塞式 */
    ssize_t NonBlockSend(const void *buf, size_t len)
    {
        if(len == 0) return 0;
        // MSG_DONTWAIT：当前IO为非阻塞方式
        return Send(buf, len, MSG_DONTWAIT);
    }
    /* 关闭套接字 */
    void Close()
    {
        if(_sockfd > 0)
        {
            close(_sockfd);
            _sockfd = -1;
        }
    }
    /* 创建一个服务器连接——监听连接 */
    bool CreateServer(const uint16_t port, const std::string& ip = "0.0.0.0", const bool block_flag = false)
    {
        // 1. 创建套接字
        if(Create() == false) return false;
        // 2. 设置套接字为非阻塞式IO
        if(block_flag)
        {
            if(NonBlock() == false) return false;
        }
        // 3. 绑定地址
        if(Bind(ip, port) == false) return false;
        // 4. 设置套接字为监听状态
        if(Listen() == false) return false;
        // 5. 启动地址重用
        if(ReuseAddress() == false) return false;

        return true;
    }
    /* 创建一个客户端连接 */
    bool CreateClient(const std::string &ip, const uint16_t port)
    {
        // 1. 创建套接字
        if(Create() == false) return false;
        // 2. 向服务器发起连接
        if(Connect(ip, port) == false) return false;

        return true;
    }
    /* 设置连接选项——开启地址端口重用 */
    bool ReuseAddress()
    {
        int opt = 1;
        int ret = setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, (socklen_t)sizeof(opt));// 设置ip地址重用
        if(ret < 0)
        {
            ERR_LOG("socket reuse addr failed [%d]: %s", errno, strerror(errno));
            return false;
        }
        opt = 1;
        ret = setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void*)&opt, (socklen_t)sizeof(opt));// 设置端口重用
        if(ret < 0)
        {
            ERR_LOG("socket reuse port failed [%d]: %s", errno, strerror(errno));
            return false;
        }
        return true;
    }
    /* 设置连接属性——非阻塞 */
    bool NonBlock()
    {
        int fl = fcntl(_sockfd, F_GETFL);
        if(fl < 0)
        {
            ERR_LOG("NonBlcok fcntl failed [%d]: %s", errno, strerror(errno));
            return false;
        }
        int ret = fcntl(_sockfd, F_SETFL, fl | O_NONBLOCK);
        if(ret < 0)
        {
            ERR_LOG("NonBlcok fcntl failed [%d]: %s", errno, strerror(errno));
            return false;
        }
        return true;
    }
    void Swap(Socket& sock)
    {
        std::swap(_sockfd, sock._sockfd);
    }
private:
    int _sockfd;
};


#endif